import * as Tapable from "tapable";

const {
  AsyncHook,
  AsyncParallelBailHook,
  AsyncParallelHook,
  AsyncSeriesBailHook,
  AsyncSeriesHook,
  AsyncSeriesLoopHook,
  AsyncSeriesWaterfallHook,
  Hook,
  MultiHook,
  SyncBailHook,
  SyncHook,
  SyncLoopHook,
  SyncWaterfallHook,
} = Tapable;
/**
 * 一个简单的汽车类，演示了如何使用 Tapable 库来实现插件系统。
 * @hook accelerate 加速
 * @hook calculateRoutes 计算路线
 * @hook brake 刹车
 */

type CalculateRoutesHooks = [
  source: string,
  target: string,
  routesList: string[],
];
type AccelerateHooks = [newSpeed: number];

type BrakeHooks = [];

class Car {
  hooks;

  constructor() {
    this.hooks = {
      calculateRoutes: new AsyncParallelHook<CalculateRoutesHooks>([
        "source",
        "target",
        "routesList",
      ]),
      accelerate: new SyncHook<AccelerateHooks>(["newSpeed"]),
      brake: new SyncHook<BrakeHooks>(),
    };
  }
}

/// /////////// ///
/// client code ///
/// /////////// ///

const myCar = new Car();

// 为 accelerate 钩子添加拦截器
myCar.hooks.accelerate.intercept({
  call: (newSpeed) => {
    console.log(`准备加速到 ${newSpeed} km/h`);
  },
  register: (tapInfo) => {
    console.log(`注册加速插件: ${tapInfo.name}`);
    return tapInfo;
  },
  tap: (tap) => {
    console.log(`执行加速插件: ${tap.name}`);
  },
});

// 为 brake 钩子添加拦截器
myCar.hooks.brake.intercept({
  call: () => {
    console.log("准备刹车");
  },
  register: (tapInfo) => {
    console.log(`注册刹车插件: ${tapInfo.name}`);
    return tapInfo;
  },
  tap: (tap) => {
    console.log(`执行刹车插件: ${tap.name}`);
  },
});

// 注册多个插件到不同的钩子
myCar.hooks.accelerate.tap("SpeedMonitorPlugin", (newSpeed) => {
  console.log(`监控速度: 当前速度 ${newSpeed} km/h`);
});

myCar.hooks.accelerate.tap("SpeedLimitPlugin", (newSpeed) => {
  if (newSpeed > 120) {
    console.log("警告: 超过速度限制!");
  }
});

myCar.hooks.brake.tap("BrakeLightPlugin", () => {
  console.log("刹车灯已开启");
});

myCar.hooks.brake.tap("ABSPlugin", () => {
  console.log("ABS系统已激活");
});

// 注册另一个路线计算插件
myCar.hooks.calculateRoutes.tapAsync(
  "WazePlugin",
  (source, target, routesList) => {
    console.log(`使用 Waze 计算从 ${source} 到 ${target} 的路线`);
    routesList.push("Waze 路线");
  },
);

// 使用 withOptions 方法添加带选项的插件
myCar.hooks.calculateRoutes
  .withOptions({
    stage: 1, // 设置执行阶段
    before: "GoogleMapsPlugin", // 在 GoogleMapsPlugin 之前执行
  })
  .tapAsync("AppleMapsPlugin", (source, target, routesList) => {
    console.log(`使用 Apple Maps 计算从 ${source} 到 ${target} 的路线`);
    routesList.push("Apple Maps 路线");
  });

myCar.hooks.calculateRoutes.tapAsync(
  "GoogleMapsPlugin",
  (source, target, routesList) => {
    console.log(`使用 Google Maps 计算从 ${source} 到 ${target} 的路线`);
    routesList.push("Google Maps 路线");
  },
);

// 实际调用钩子
console.log("\n--- 模拟汽车操作 ---");

// 模拟加速
myCar.hooks.accelerate.call(80);
myCar.hooks.accelerate.call(130);

// 模拟刹车
myCar.hooks.brake.call();

// 模拟路线计算
const routes: string[] = [];
myCar.hooks.calculateRoutes.callAsync("北京", "上海", routes, (error) => {
  if (error) {
    console.error("路线计算出错:", error);
  } else {
    console.log("计算出的路线:", routes);
  }
});

// 检查钩子是否被使用
console.log("\n--- 钩子使用状态 ---");
console.log(
  "calculateRoutes 是否被使用:",
  myCar.hooks.calculateRoutes.isUsed(),
);
console.log("accelerate 是否被使用:", myCar.hooks.accelerate.isUsed());
console.log("brake 是否被使用:", myCar.hooks.brake.isUsed());

// 查看已注册的插件
console.log("\n--- 已注册的插件 ---");
console.log(
  "calculateRoutes 插件:",
  myCar.hooks.calculateRoutes.taps.map((t) => t.name),
);
console.log(
  "accelerate 插件:",
  myCar.hooks.accelerate.taps.map((t) => t.name),
);
console.log(
  "brake 插件:",
  myCar.hooks.brake.taps.map((t) => t.name),
);
